package jmine.tec.web.servlet.filter.resolver;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * @author takeshi
 */
public class ThreadBoundRequestFilter implements Filter {

    /**
     * 
     */
    public void destroy() {
    }

    private ApplicationContext appContext;

    private List<ThreadBoundRequestResolver> resolvers;

    /**
     * @param request the {@link ServletRequest}
     * @param response the {@link ServletResponse}
     * @param chain the {@link FilterChain}
     * @throws IOException e
     * @throws ServletException e
     */
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException,
            ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        for (ThreadBoundRequestResolver tbrr : this.getResolvers()) {
            tbrr.setInstance(req);
        }
        try {
            chain.doFilter(request, response);
        } finally {
            for (ThreadBoundRequestResolver tbrr : this.getResolvers()) {
                tbrr.clearCurrentInstance();
            }
        }
    }

    /**
     * @return {@link List}
     */
    private List<ThreadBoundRequestResolver> getResolvers() {
        if (this.resolvers == null) {
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.appContext, ThreadBoundRequestResolver.class);
            this.resolvers = new ArrayList<ThreadBoundRequestResolver>(beanNames.length);
            for (String name : beanNames) {
                this.resolvers.add((ThreadBoundRequestResolver) this.appContext.getBean(name));
            }
        }
        return this.resolvers;
    }

    /**
     * @param filterConfig the {@link FilterConfig}
     * @throws ServletException in case of exception
     */
    public void init(final FilterConfig filterConfig) throws ServletException {
        this.appContext = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
    }

    /**
     * @return the appContext
     */
    public ApplicationContext getAppContext() {
        return this.appContext;
    }

    /**
     * @param appContext the appContext to set
     */
    public void setAppContext(final ApplicationContext appContext) {
        this.appContext = appContext;
    }

}
